package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"

	adminRouters "likeadmin/admin/routers"
	admin "likeadmin/admin/service"
	"likeadmin/admin/service/cron"
	clientRouters "likeadmin/client/routers"
	client "likeadmin/client/service"
	"likeadmin/config"
	"likeadmin/core"
	"likeadmin/core/response"
	genRouters "likeadmin/generator/routers"
	gen "likeadmin/generator/service"
	"likeadmin/middleware"
)

// 应用常量
const (
	ServerReadTimeout    = 10 * time.Second
	ServerWriteTimeout   = 10 * time.Second
	ServerMaxHeaderBytes = 1 << 20
	CronShutdownTimeout  = 5 * time.Second
	HealthCheckInterval  = 30 * time.Minute
	InitialStatusDelay   = 2 * time.Second
)

// Application 应用主结构体
type Application struct {
	server *http.Server
	router *gin.Engine
}

// initializeDI 初始化依赖注入
func initializeDI() error {
	core.Logger.Info("开始初始化依赖注入")

	// 收集所有初始化函数
	initFunctions := []interface{}{
		core.GetDB,
	}
	initFunctions = append(initFunctions, admin.InitFunctions...)
	initFunctions = append(initFunctions, gen.InitFunctions...)
	initFunctions = append(initFunctions, client.InitFunctions...)

	// 注册所有依赖
	for i, fn := range initFunctions {
		if err := core.ProvideForDI(fn); err != nil {
			return fmt.Errorf("注册依赖函数 %d 失败: %w", i, err)
		}
	}

	core.Logger.Info("依赖注入初始化完成", zap.Int("function_count", len(initFunctions)))
	return nil
}

// initializeRouter 初始化路由
func initializeRouter() *gin.Engine {
	core.Logger.Info("开始初始化路由", zap.String("gin_mode", config.Config.GinMode))

	gin.SetMode(config.Config.GinMode)
	router := gin.New()

	// 注册中间件
	router.Use(
		gin.Logger(),
		middleware.Cors(),
		middleware.ErrorRecover(),
	)

	// 演示模式中间件
	if config.Config.DisallowModify {
		router.Use(middleware.ShowMode())
		core.Logger.Info("演示模式已启用")
	}

	// 静态文件服务
	router.Static(config.Config.PublicPrefix, config.Config.UploadDirectory)
	router.Static(config.Config.StaticPath, config.Config.StaticDirectory)
	core.Logger.Info("静态文件服务已配置",
		zap.String("public_prefix", config.Config.PublicPrefix),
		zap.String("static_path", config.Config.StaticPath))

	// 特殊异常处理
	router.NoMethod(response.NoMethod)
	router.NoRoute(response.NoRoute)

	// 注册API路由
	apiGroup := router.Group("/api")
	registerGroupBaseRouters(apiGroup, adminRouters.InitRouters, "Admin")
	registerGroupBaseRouters(apiGroup, genRouters.InitRouters, "Generator")

	// 注册客户端路由
	clientGroup := router.Group("/client")
	registerGroupBaseRouters(clientGroup, clientRouters.InitRouters, "Client")

	core.Logger.Info("路由初始化完成")
	return router
}

// registerGroupBaseRouters 注册基于 GroupBase 的路由
func registerGroupBaseRouters(group *gin.RouterGroup, routers []*core.GroupBase, module string) {
	for _, routerBase := range routers {
		core.RegisterGroup(group, routerBase)
	}
	core.Logger.Info("路由组注册完成",
		zap.String("module", module),
		zap.Int("router_count", len(routers)))
}

// initializeServer 初始化HTTP服务器
func initializeServer(router *gin.Engine) *http.Server {
	addr := ":" + strconv.Itoa(config.Config.ServerPort)

	core.Logger.Info("HTTP服务器初始化完成",
		zap.String("address", addr),
		zap.String("mode", config.Config.GinMode))

	return &http.Server{
		Addr:           addr,
		Handler:        router,
		ReadTimeout:    ServerReadTimeout,
		WriteTimeout:   ServerWriteTimeout,
		MaxHeaderBytes: ServerMaxHeaderBytes,
	}
}

// initializeCronSystem 初始化定时任务系统
func initializeCronSystem() error {
	core.Logger.Info("开始初始化定时任务系统")

	// 初始化定时任务
	core.InitCron()

	// 获取定时任务服务实例
	cronService := core.MustGetDI[*cron.TaskService]()

	// 注册所有任务
	cronService.RegisterAllTasks()

	// 启动定时任务调度器
	core.Cron.Start()

	// 验证任务注册状态
	entries := core.Cron.Entries()
	if len(entries) > 0 {
		core.Logger.Info("定时任务系统初始化完成",
			zap.Int("task_count", len(entries)))
	} else {
		core.Logger.Warn("定时任务系统已启动，但未注册任何任务")
	}

	return nil
}

// startCronMonitoring 启动定时任务监控
func startCronMonitoring() {
	core.Logger.Info("启动定时任务监控")

	// 延迟报告初始状态
	go func() {
		time.Sleep(InitialStatusDelay)
		reportCronStatus()
	}()

	// 定期健康检查
	go func() {
		ticker := time.NewTicker(HealthCheckInterval)
		defer ticker.Stop()

		for range ticker.C {
			entries := core.Cron.Entries()
			core.Logger.Info("定时任务健康检查",
				zap.Int("active_tasks", len(entries)),
				zap.Time("check_time", time.Now()))
		}
	}()
}

// reportCronStatus 报告定时任务状态
func reportCronStatus() {
	entries := core.Cron.Entries()

	core.Logger.Info("定时任务状态报告开始",
		zap.Int("total_tasks", len(entries)))

	for i, entry := range entries {
		// 使用安全的字段访问方式，直接传递字段而不是切片
		logFields := []zap.Field{
			zap.Int("index", i+1),
			zap.Time("next_run", entry.Next),
		}

		// 尝试获取 Prev 时间
		if !entry.Prev.IsZero() {
			logFields = append(logFields, zap.Time("prev_run", entry.Prev))
		}

		// 安全获取 Entry ID
		if entryID := getEntryID(entry); entryID != "" {
			logFields = append(logFields, zap.String("entry_id", entryID))
		}

		// 使用展开操作符传递字段
		core.Logger.Info("定时任务详情", logFields)
	}

	core.Logger.Info("定时任务状态报告结束")
}

// getEntryID 安全获取 Entry ID
func getEntryID(entry interface{}) string {
	// 使用类型断言尝试获取ID
	switch e := entry.(type) {
	case interface{ GetID() int }:
		return fmt.Sprintf("%d", e.GetID())
	case interface{ ID() int }:
		return fmt.Sprintf("%d", e.ID())
	case interface{ GetEntryID() string }:
		return e.GetEntryID()
	case interface{ EntryID() string }:
		return e.EntryID()
	default:
		// 如果无法获取ID，返回空字符串
		return ""
	}
}

// gracefulShutdownCron 优雅关闭定时任务
func gracefulShutdownCron() {
	core.Logger.Info("开始停止定时任务调度器...")

	stopCtx := core.Cron.Stop()

	select {
	case <-stopCtx.Done():
		core.Logger.Info("所有定时任务已安全停止")
	case <-time.After(CronShutdownTimeout):
		core.Logger.Warn("定时任务停止超时，强制退出")
	}

	core.Logger.Info("定时任务调度器已停止")
}

// startProfiling 启动性能监控
func startProfiling() {
	profilerAddr := "localhost:6060"
	go func() {
		core.Logger.Info("性能监控服务启动", zap.String("address", profilerAddr))
		if err := http.ListenAndServe(profilerAddr, nil); err != nil {
			core.Logger.Error("性能监控服务启动失败", zap.Error(err))
		}
	}()
}

// closeDatabase 关闭数据库连接
func closeDatabase() {
	if db := core.GetDB(); db != nil {
		sqlDB, err := db.DB()
		if err != nil {
			core.Logger.Error("获取数据库实例失败", zap.Error(err))
			return
		}

		if err := sqlDB.Close(); err != nil {
			core.Logger.Error("关闭数据库连接失败", zap.Error(err))
		} else {
			core.Logger.Info("数据库连接已关闭")
		}
	}
}

// waitForShutdown 等待优雅关闭信号
func (app *Application) waitForShutdown() {
	// 创建信号监听通道
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

	// 等待关闭信号
	sig := <-quit
	core.Logger.Info("接收到关闭信号", zap.String("signal", sig.String()))

	// 创建关闭超时上下文
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// 优雅关闭HTTP服务器
	if err := app.server.Shutdown(ctx); err != nil {
		core.Logger.Error("HTTP服务器关闭失败", zap.Error(err))
	} else {
		core.Logger.Info("HTTP服务器已优雅关闭")
	}
}

// initialize 应用初始化
func initialize() (*Application, error) {
	// 初始化依赖注入
	if err := initializeDI(); err != nil {
		return nil, fmt.Errorf("依赖注入初始化失败: %w", err)
	}

	// 初始化路由
	router := initializeRouter()

	// 初始化服务器
	server := initializeServer(router)

	return &Application{
		server: server,
		router: router,
	}, nil
}

// run 运行应用
func (app *Application) run() error {
	// 启动性能监控
	startProfiling()

	// 初始化定时任务系统
	if err := initializeCronSystem(); err != nil {
		return fmt.Errorf("定时任务系统初始化失败: %w", err)
	}

	// 启动定时任务监控
	startCronMonitoring()

	// 启动HTTP服务器
	core.Logger.Info("应用服务启动成功",
		zap.String("address", app.server.Addr),
		zap.Time("start_time", time.Now()))

	// 在goroutine中启动服务器，以便主线程可以监听关闭信号
	serverErr := make(chan error, 1)
	go func() {
		if err := app.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			serverErr <- err
		}
	}()

	// 等待关闭信号或服务器错误
	select {
	case err := <-serverErr:
		return fmt.Errorf("HTTP服务器运行失败: %w", err)
	default:
		// 等待优雅关闭
		app.waitForShutdown()
		return nil
	}
}

func main() {
	// 确保日志缓冲刷新
	defer core.Logger.Sync()

	// 程序退出时资源清理
	defer func() {
		gracefulShutdownCron()
		closeDatabase()
		core.Logger.Info("应用程序已完全关闭")
	}()

	// 应用初始化
	app, err := initialize()
	if err != nil {
		core.Logger.Error("应用初始化失败", zap.Error(err))
		log.Fatalf("应用初始化失败: %v", err)
	}

	// 运行应用
	if err := app.run(); err != nil {
		core.Logger.Error("应用运行失败", zap.Error(err))
		log.Fatalf("应用运行失败: %v", err)
	}
}
